const { reject, initial } = require("lodash");

const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';

class MyPromise {
    /**
     * 构造Promise对象
     * 
     * @param executor 执行器 
     */
    constructor(executor) {
        this.init();

        executor(result => {
            if (this.status != PENDING) {
                // Promise的状态已经确定，不允许再更改
                return;
            }

            this.status = FULFILLED;
            this.result = result;
            this.runCallback(this.result, this.callbackForSuccess);
        }, reason => {
            if (this.status != PENDING) {
                // Promise的状态已经确定，不允许再更改
                return;
            }

            this.status = REJECTED;
            this.reason = reason;
            this.runCallback(this.reason, this.callbackForFailure)
        })
    }

    /**
     * 初始化Promise
     */
    init() {
        /**
         * Promise的状态，初始状态设为PENDING
         */
        this.status = PENDING;

        /**
         * Promise的任务队列，用于记录同一个Promise上面的then调用的成功回调函数
         */
        this.callbackForSuccess = [];

        /**
         * Promise的任务队列，用于记录同一个Promise上面的then调用的失败回调函数
         */
        this.callbackForFailure = [];

        /**
         * Promise成功执行的结果
         */
        this.result = undefined;

        /**
         * Promise执行失败的原因
         */
        this.reason = undefined;
    }

    /**
     * 执行then上面注册的回调函数
     * 
     * @param value Promise执行的结果
     * @param callbacks 回调函数数组
     */
    runCallback(value, callbacks) {
        callbacks.forEach(callback => callback(value));
    }

    /**
     * 实现Promise的then方法
     * 
     * @param successCallback Promise执行成功的回调函数
     * @param failCallback Promise执行失败的回调函数
     * @return 新的Promise
     */
    then(successCallback, failCallback) {
        // 参数不是函数，直接返回它自己
        successCallback = typeof successCallback !== 'function' ? () => successCallback : successCallback;
        failCallback = typeof failCallback !== 'function' ? () => failCallback : failCallback;

        let newPromise = new MyPromise((resolve, reject) => {
            if (this.status == FULFILLED) {
                // Promise执行成功，直接调用成功回调函数
                // 使用setTimeout异步调用，确保newPromise初始化完成，可以用于和回调函数的返回值比较
                setTimeout(() => {
                    try {
                        let result = successCallback(this.result);
                        this.resolvePromise(result, resolve, reject, newPromise);
                    } catch (e) {
                        // 处理成功回调函数抛出的异常
                        reject(e);
                    }
                }, 0);

                return;
            }

            if (this.status == REJECTED) {
                setTimeout(() => {
                    try {
                        let result = failCallback(this.reason);
                        this.resolvePromise(result, resolve, reject, newPromise);
                    } catch (e) {
                        reject(e);
                    }
                }, 0);

                return;
            }

            // Promise还没执行完成，将回调函数放到任务队列
            this.callbackForSuccess.push(() => {
                setTimeout(() => {
                    try {
                        let result = successCallback(this.result);
                        this.resolvePromise(result, resolve, reject, newPromise);
                    } catch (e) {
                        // 处理成功回调函数抛出的异常
                        reject(e);
                    }
                }, 0);
            });

            this.callbackForFailure.push(() => {
                setTimeout(() => {
                    try {
                        let result = failCallback(this.reason);
                        this.resolvePromise(result, resolve, reject, newPromise);
                    } catch (e) {
                        reject(e);
                    }
                }, 0);
            });

        });

        return newPromise;
    }

    /**
     * 处理回调函数的返回值
     * 
     * @param result 回调函数的返回值
     * @param resolve 回调函数对应的Promise的resolve方法
     * @param reject 回调函数对应的Promise的reject方法
     * @param newPromise 回调函数对应的Promise
     */
    resolvePromise(result, resolve, reject, newPromise) {
        if (result == newPromise) {
            throw new TypeError("Invalid return value!");
        }

        // 返回值是Promise，将newPromise的resolve和reject函数注册到该Promise
        if (result instanceof MyPromise) {
            result.then(resolve, reject);
            return;
        }

        resolve(result);
    }

    /**
     * 实现Promise的finally方法
     * 
     * @param callback 回调函数
     * @return 新的Promise
     */
    finally(callback) {
        // 无论成功还是失败，都执行回调函数，将Promise的结果返回
        return this.then(result => {
            callback();
            return result;
        }, reason => {
            callback();
            throw reason;
        });
    }

    /**
     * 实现Promise的catch方法
     * 
     * @param callback 回调函数
     * @return 新的Promise
     */
    catch(callback) {
        return this.then(undefined, callback);
    }

    /**
     * 实现Promise的all方法，等待所有Promise执行完，按顺序返回结果
     * 
     * @param array 要执行的Promise
     */
    static all(array) {
        return new MyPromise((resolve, reject) => {
            let result = []; // 用来存放Promise的执行结果
            let num = 0;

            function addData(idx, value) {
                result[idx] = value;
                ++num;

                // 所有Promise都执行完了
                if (num == array.length) {
                    resolve(result);
                }
            }

            for (let idx = 0; idx < array.length; ++idx) {
                if (array[idx] instanceof MyPromise) {
                    // 注册回调函数，将array[idx]的结果保存到对应的位置
                    array[idx].then(value => addData(idx, value), reason => reject(reason));
                    continue;
                }

                // array[idx]不是Promise，直接作为结果保存
                addData(idx, array[idx]);
            }
        })
    }

    /**
     * 实现Promise的resolve方法，将给定的值转换为Promise
     * 
     * @param value 给定的值
     * @return 新的Promise
     */
    static resolve(value) {
        if (value instanceof MyPromise) {
            // 给定的值是Promise，直接返回
            return value;
        }

        return new MyPromise((resolve, reject) => {
            // 直接将给定的值作为Promise的结果
            resolve(value);
        });
    }
}

// 测试用例
new MyPromise((resolve, reject) => {
    setTimeout(() => {
        resolve(10);
    }, 1000);
}).then(value => {
    console.log(value);
    return new MyPromise((resolve, reject) => {
        setTimeout(() => resolve(20), 1000);
    });
}).then(value => console.log(value))
.finally(() => console.log("finally"));

MyPromise.resolve(4).then(value => console.log(value))
.then(value => {throw 'error'})
.catch(reason => console.log(reason));